package com.jzo2o.redis.sync.impl;

import cn.hutool.extra.spring.SpringUtil;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.redis.handler.SyncProcessHandler;
import com.jzo2o.redis.model.SyncMessage;
import com.jzo2o.redis.sync.SyncThread;
import com.jzo2o.redis.utils.RedisSyncQueueUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 同步线程抽象基类，实现 SyncThread 接口
 * 定义所有同步线程的基础规范与通用功能，采用泛型设计支持多种数据类型
 */
@Slf4j
@Data
public abstract class AbstractSyncThread<T> implements SyncThread {

    private static final String REDIS_KEY_FORMAT = "%s:%s:{%s}"; // redis 键格式
    private static final String LOCK_PREFIX = "LOCK:"; // 分布式锁前缀
    private final RedissonClient redissonClient; // redisson 客户端
    private final String queueName; // 队列名称
    private final int index; // 队列索引序号

    public AbstractSyncThread(RedissonClient redissonClient, String queueName, int index) {
        this.redissonClient = redissonClient;
        this.queueName = queueName;
        this.index = index;
    }

    /**
     * 线程执行逻辑
     * 1. 获取分布式锁确保线程安全
     * 2. 循环获取并处理队列数据
     * 3. 完成后释放锁
     */
    @Override
    public void run() {
        // 1.使用redssion看门狗模式锁定当前序号的队列
        String lockName = LOCK_PREFIX + RedisSyncQueueUtils.getQueueRedisKey(queueName, index);
        RLock lock = redissonClient.getLock(lockName);
        try {
            if(!lock.tryLock(0, -1, TimeUnit.SECONDS)){
                return;
            }
            // 2.获取数据
            List<SyncMessage<T>> data = null;
            while (CollUtils.isNotEmpty(data = this.getData())) {
                // 3.处理数据
                this.process(data);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        } catch (Exception e){
            return;
        } finally {
            // 4.解锁
            if (lock != null && lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    /**
     * 获取待处理数据
     * @return 同步消息列表
     */
    protected abstract List<SyncMessage<T>> getData();

    /**
     * 处理数据
     * @param data 待处理的同步消息列表
     * @return 处理结果 (true/false)
     */
    protected abstract boolean process(List<SyncMessage<T>> data);

    /**
     * 获取同步处理器
     * 优先按队列名获取，获取不到则抛出异常
     * @return 同步处理器实例
     */
    protected SyncProcessHandler<T> getSyncProcessHandler() {
        SyncProcessHandler syncProcessHandler = SpringUtil.getBean(queueName, SyncProcessHandler.class);
        if (syncProcessHandler != null) {
            return syncProcessHandler;
        }
        throw new RuntimeException("未找到名称（" + queueName + "）redis 队列数据处理器");
    }
}
